{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "f04dd603-a2d1-48ce-8c17-9f1dba8de1ee",
   "metadata": {},
   "source": [
    "Chapter 05\n",
    "\n",
    "# 伴随矩阵法求解逆矩阵\n",
    "《线性代数》 | 鸢尾花书：数学不难"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ccafb456-2453-4c82-8a65-b1963a370cb2",
   "metadata": {},
   "source": [
    "这段代码的核心目的是从数学角度推导并实现一个矩阵的逆矩阵计算过程，遵循的是线性代数中的经典方法，即通过余子式和伴随矩阵的计算得到逆矩阵。以下是详细的数学描述。\n",
    "\n",
    "---\n",
    "\n",
    "### 1. 余子矩阵的提取\n",
    "\n",
    "对于一个 $n \\times n$ 的方阵 $A = [a_{ij}]$，其某个元素 $a_{ij}$ 对应的**余子矩阵**（Minor）是删除该元素所在的第 $i$ 行和第 $j$ 列后得到的 $(n-1) \\times (n-1)$ 矩阵。代码中的 `get_minor(matrix, row, col)` 实现了这一操作。\n",
    "\n",
    "如果矩阵 $A$ 为：\n",
    "$$\n",
    "A =\n",
    "\\begin{bmatrix}\n",
    "a_{11} & a_{12} & a_{13} \\\\\n",
    "a_{21} & a_{22} & a_{23} \\\\\n",
    "a_{31} & a_{32} & a_{33}\n",
    "\\end{bmatrix}\n",
    "$$\n",
    "则删除第一行第二列 ($a_{12}$) 后的余子矩阵为：\n",
    "$$\n",
    "M_{12} =\n",
    "\\begin{bmatrix}\n",
    "a_{21} & a_{23} \\\\\n",
    "a_{31} & a_{33}\n",
    "\\end{bmatrix}\n",
    "$$\n",
    "\n",
    "---\n",
    "\n",
    "### 2. 行列式的计算（Laplace 展开）\n",
    "\n",
    "代码的 `determinant(matrix)` 递归实现了 **Laplace 展开** 计算行列式：\n",
    "\n",
    "1. 对于 $1 \\times 1$ 矩阵，行列式为矩阵唯一元素：\n",
    "   $$\n",
    "   \\det(A) = a_{11}\n",
    "   $$\n",
    "2. 对于 $2 \\times 2$ 矩阵：\n",
    "   $$\n",
    "   \\det(A) = a_{11} a_{22} - a_{12} a_{21}\n",
    "   $$\n",
    "3. 对于一般的 $n \\times n$ 矩阵，采用 Laplace 展开：\n",
    "   $$\n",
    "   \\det(A) = \\sum_{j=1}^{n} (-1)^{1+j} a_{1j} \\det(M_{1j})\n",
    "   $$\n",
    "   其中，$M_{1j}$ 是删除第 1 行第 $j$ 列后的余子矩阵，$(-1)^{1+j}$ 是符号调整项。\n",
    "\n",
    "代码中的 `determinant(matrix)` 通过递归方式计算这个展开式。\n",
    "\n",
    "---\n",
    "\n",
    "### 3. 代数余子式矩阵（Cofactor Matrix）\n",
    "\n",
    "代数余子式（Cofactor）是余子式 $M_{ij}$ 乘以符号调整项：\n",
    "$$\n",
    "C_{ij} = (-1)^{i+j} \\det(M_{ij})\n",
    "$$\n",
    "代码 `cofactor_matrix(matrix)` 计算了整个矩阵的代数余子式矩阵：\n",
    "$$\n",
    "C =\n",
    "\\begin{bmatrix}\n",
    "C_{11} & C_{12} & C_{13} \\\\\n",
    "C_{21} & C_{22} & C_{23} \\\\\n",
    "C_{31} & C_{32} & C_{33}\n",
    "\\end{bmatrix}\n",
    "$$\n",
    "\n",
    "---\n",
    "\n",
    "### 4. 伴随矩阵（Adjugate Matrix）\n",
    "\n",
    "伴随矩阵（Adjugate 或 Adjoint）是代数余子式矩阵 $C$ 的转置：\n",
    "$$\n",
    "\\operatorname{adj}(A) = C^T\n",
    "$$\n",
    "代码 `adjugate_matrix(matrix)` 通过 `.T` 计算这个转置操作。\n",
    "\n",
    "---\n",
    "\n",
    "### 5. 逆矩阵的计算\n",
    "\n",
    "当行列式 $\\det(A) \\neq 0$ 时，矩阵 $A$ 可逆，逆矩阵由：\n",
    "$$\n",
    "A^{-1} = \\frac{1}{\\det(A)} \\operatorname{adj}(A)\n",
    "$$\n",
    "代码 `inverse_matrix(matrix)` 计算了这个公式。如果 $\\det(A) = 0$，则抛出异常，表示矩阵不可逆。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d6fcf357-6abe-4cff-b235-93d52b979c36",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "27d59ddc-4069-4f18-a921-ad1621caba7b",
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_minor(matrix, row, col):\n",
    "    \"\"\"\n",
    "    提取余子矩阵，去掉指定的行和列\n",
    "    \"\"\"\n",
    "    return np.delete(np.delete(matrix, row, axis=0), col, axis=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7f589490-a87c-423f-b882-6cb6a94afb15",
   "metadata": {},
   "outputs": [],
   "source": [
    "def determinant(matrix):\n",
    "    \"\"\"\n",
    "    递归计算行列式（Laplace 展开）\n",
    "    \"\"\"\n",
    "    n = matrix.shape[0]\n",
    "    if n == 1:\n",
    "        return matrix[0, 0]\n",
    "    if n == 2:\n",
    "        return matrix[0, 0] * matrix[1, 1] - matrix[0, 1] * matrix[1, 0]\n",
    "    \n",
    "    det = 0\n",
    "    for col in range(n):\n",
    "        minor = get_minor(matrix, 0, col)  # 提取余子矩阵\n",
    "        cofactor = ((-1) ** col) * determinant(minor)  # 计算代数余子式\n",
    "        det += matrix[0, col] * cofactor  # 计算行列式\n",
    "    \n",
    "    return det"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f4025d29-2988-4cb5-a125-359078dbad07",
   "metadata": {},
   "outputs": [],
   "source": [
    "def cofactor_matrix(matrix):\n",
    "    \"\"\"\n",
    "    计算代数余子式矩阵\n",
    "    \"\"\"\n",
    "    n = matrix.shape[0]\n",
    "    cof_matrix = np.zeros((n, n))\n",
    "    \n",
    "    for row in range(n):\n",
    "        for col in range(n):\n",
    "            minor = get_minor(matrix, row, col)  # 提取余子矩阵\n",
    "            cof_matrix[row, col] = ((-1) ** (row + col)) * determinant(minor)  # 计算代数余子式\n",
    "    \n",
    "    return cof_matrix"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c2b80072-48d0-42fa-aea7-e29a3bdb177b",
   "metadata": {},
   "outputs": [],
   "source": [
    "def adjugate_matrix(matrix):\n",
    "    \"\"\"\n",
    "    计算伴随矩阵，即代数余子式矩阵的转置\n",
    "    \"\"\"\n",
    "    return cofactor_matrix(matrix).T"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1b78cf81-7f49-4078-9ea2-87e1ef95fc1b",
   "metadata": {},
   "outputs": [],
   "source": [
    "def inverse_matrix(matrix):\n",
    "    \"\"\"\n",
    "    计算矩阵的逆矩阵（如果存在）\n",
    "    \"\"\"\n",
    "    det = determinant(matrix)\n",
    "    if det == 0:\n",
    "        raise ValueError(\"矩阵不可逆（行列式为0）\")\n",
    "    \n",
    "    adj = adjugate_matrix(matrix)  # 计算伴随矩阵\n",
    "    return adj / det  # 计算逆矩阵"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2c6460d4-e109-457d-8329-72401ce657ec",
   "metadata": {},
   "source": [
    "## 测试"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1a46fe89-2a84-4483-987b-fb25229c71bd",
   "metadata": {},
   "outputs": [],
   "source": [
    "A = np.array([[1, 2, 3], \n",
    "              [3, 0, 1], \n",
    "              [1, 2, 1]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f9009bc8-a59c-4559-a137-8260630f4aeb",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-0.16666667,  0.33333333,  0.16666667],\n",
       "       [-0.16666667, -0.16666667,  0.66666667],\n",
       "       [ 0.5       ,  0.        , -0.5       ]])"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A_inv = inverse_matrix(A)\n",
    "A_inv"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "954b7525-dcef-47cb-af13-40c741ca3891",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "070c3389-8048-43a3-baa7-6666009bce96",
   "metadata": {},
   "source": [
    "作者\t**生姜DrGinger**  \n",
    "脚本\t**生姜DrGinger**  \n",
    "视频\t**崔崔CuiCui**  \n",
    "开源资源\t[**GitHub**](https://github.com/Visualize-ML)  \n",
    "平台\t[**油管**](https://www.youtube.com/@DrGinger_Jiang)\t\t\n",
    "\t\t[**iris小课堂**](https://space.bilibili.com/3546865719052873)\t\t\n",
    "\t\t[**生姜DrGinger**](https://space.bilibili.com/513194466)  "
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda env:base] *",
   "language": "python",
   "name": "conda-base-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
